/* Classic Ladder Project */
/* Copyright (C) 2001-2012 Marc Le Douarain */
/* http://membres.lycos.fr/mavati/classicladder/ */
/* http://www.sourceforge.net/projects/classicladder */
/* July 2003 */
/* ----------------------------- */
/* Editor Config - GTK interface */
/* ----------------------------- */
/* This library is free software; you can redistribute it and/or */
/* modify it under the terms of the GNU Lesser General Public */
/* License as published by the Free Software Foundation; either */
/* version 2.1 of the License, or (at your option) any later version. */

/* This library is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU */
/* Lesser General Public License for more details. */

/* You should have received a copy of the GNU Lesser General Public */
/* License along with this library; if not, write to the Free Software */
/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#include <gtk/gtk.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "classicladder.h"
#include "manager.h"
#include "edit.h"
#include "hardware.h"
#include "global.h"
#include "classicladder_gtk.h"
#include "vars_names.h"
#ifdef COMPLETE_PLC
#include "log_events.h"
#endif
#include "socket_modbus_master.h"
#include "config_gtk.h"

#ifdef OLD_TIMERS_MONOS_SUPPORT
#define NBR_OBJECTS_GENERAL 19
#else
#define NBR_OBJECTS_GENERAL 16
#endif
GtkWidget *LabelParam[ NBR_OBJECTS_GENERAL ],*ValueParam[ NBR_OBJECTS_GENERAL ];

static char * Devices[] = { "None", "DirectPortAccess", "DirectPortConfig", 
#ifdef COMEDI_SUPPORT
"/dev/comedi0", "/dev/comedi1", "/dev/comedi2", "/dev/comedi3",
#endif
 NULL };

#define NBR_IO_PARAMS 7
GtkWidget *InputParamEntry[ NBR_INPUTS_CONF ][ NBR_IO_PARAMS ];
GtkWidget *InputDeviceParam[ NBR_INPUTS_CONF ];
GtkWidget *InputFlagParam[ NBR_INPUTS_CONF ];

GtkWidget *OutputParamEntry[ NBR_OUTPUTS_CONF ][ NBR_IO_PARAMS ];
GtkWidget *OutputDeviceParam[ NBR_OUTPUTS_CONF ];
GtkWidget *OutputFlagParam[ NBR_OUTPUTS_CONF ];

#ifdef MODBUS_IO_MASTER
// ModbusReqType must be in the same order as MODBUS_REQ_ in protocol_modbus_master.h
static char * ModbusReqType[] = { "ReadInputs (to %I)", "WriteCoils (from %Q)", "ReadInputRegs (to %IW)", "WriteHoldRegs (from %QW)", "ReadCoils (to %Q)", "ReadHoldRegs (to %QW)", "ReadStatus (to %IW)", "Diagnostic (from %IW/to %QW - 1stEle=sub-code used)", NULL };
#define NBR_MODBUS_REQ_PARAMS 6
GtkWidget *ModbusReqParamEntry[ NBR_MODBUS_MASTER_REQ ][ NBR_MODBUS_REQ_PARAMS ];
#define NBR_MODBUS_SLAVES_PARAMS 4
GtkWidget *ModbusSlaveParamEntry[ NBR_MODBUS_SLAVES ][ NBR_MODBUS_SLAVES_PARAMS ];
//GtkWidget *SerialPortEntry;
//GtkWidget *SerialSpeedEntry;
//GtkWidget *PauseInterFrameEntry;
//GtkWidget *DebugLevelEntry;
#define NBR_COM_PARAMS 17
#define NBR_RADIO_BUT_COM_PARAMS 5
GtkWidget *EntryComParam[ NBR_COM_PARAMS ];
GtkWidget *RadioButComParams[ NBR_COM_PARAMS ][ NBR_RADIO_BUT_COM_PARAMS ];
GtkWidget *ComboSlaveStatsSelect;
GtkWidget * LabelStatsResults;
#endif

#define NBR_CONFIG_EVENTS_PARAMS 5
GtkWidget *EventConfigParamEntry[ NBR_CONFIG_EVENTS_LOG ][ NBR_CONFIG_EVENTS_PARAMS ];

GtkWidget *ConfigWindow;

void ButtonSetDefaultProject_click( void )
{
	strcpy( Preferences.DefaultProjectFileNameToLoadAtStartup, InfosGene->CurrentProjectFileName );
	gtk_entry_set_text( GTK_ENTRY(ValueParam[NBR_OBJECTS_GENERAL-1]), Preferences.DefaultProjectFileNameToLoadAtStartup );
}
void ButtonClearDefaultProject_click( void )
{
	Preferences.DefaultProjectFileNameToLoadAtStartup[ 0 ] = '\0';
	gtk_entry_set_text( GTK_ENTRY(ValueParam[NBR_OBJECTS_GENERAL-1]), Preferences.DefaultProjectFileNameToLoadAtStartup );
}

GtkWidget * CreateGeneralParametersPage( void )
{
	GtkWidget *vbox;
	GtkWidget *hbox[ NBR_OBJECTS_GENERAL ];
	int NumObj;

	vbox = gtk_vbox_new (FALSE, 0);

	for (NumObj=0; NumObj<NBR_OBJECTS_GENERAL; NumObj++)
	{
		char BuffLabel[ 50 ];
		char BuffValue[ 200 ];
                
		int InfoUsed = 0;
		hbox[NumObj] = gtk_hbox_new (FALSE, 0);
		gtk_container_add (GTK_CONTAINER (vbox), hbox[NumObj]);

		switch( NumObj )
		{
			case 1:
				sprintf( BuffLabel, "Periodic Refresh Rate 'inputs scan' (milliseconds)" );
				sprintf( BuffValue, "%d", GeneralParamsMirror.PeriodMilliSecsTaskScanInputs );
				break;
			case 2:
				sprintf( BuffLabel, "Periodic Refresh Rate 'logic' (milliseconds)" );
				sprintf( BuffValue, "%d", GeneralParamsMirror.PeriodMilliSecsTaskLogic );
				break;
			case 3:
				InfoUsed = GetNbrRungsDefined( )*100/InfosGene->GeneralParams.SizesInfos.nbr_rungs;
				sprintf( BuffLabel, "Nbr.rungs (%d%c used - current alloc=%d)", InfoUsed,'%', InfosGene->GeneralParams.SizesInfos.nbr_rungs );
				sprintf( BuffValue, "%d", GeneralParamsMirror.SizesInfos.nbr_rungs );
				break;
			case 4:
				sprintf( BuffLabel, "Nbr.Bits (current alloc=%d)", InfosGene->GeneralParams.SizesInfos.nbr_bits );
				sprintf( BuffValue, "%d", GeneralParamsMirror.SizesInfos.nbr_bits );
				break;
			case 5:
				sprintf( BuffLabel, "Nbr.Words (current alloc=%d)", InfosGene->GeneralParams.SizesInfos.nbr_words );
				sprintf( BuffValue, "%d", GeneralParamsMirror.SizesInfos.nbr_words );
				break;
			case 6:
				sprintf( BuffLabel, "Nbr.Counters (current alloc=%d)", InfosGene->GeneralParams.SizesInfos.nbr_counters );
				sprintf( BuffValue, "%d", GeneralParamsMirror.SizesInfos.nbr_counters );
				break;
			case 7:
				sprintf( BuffLabel, "Nbr.Timers IEC (current alloc=%d)", InfosGene->GeneralParams.SizesInfos.nbr_timers_iec );
				sprintf( BuffValue, "%d", GeneralParamsMirror.SizesInfos.nbr_timers_iec );
				break;
			case 8:
				sprintf( BuffLabel, "Nbr.Phys.Inputs (current alloc=%d)", InfosGene->GeneralParams.SizesInfos.nbr_phys_inputs );
				sprintf( BuffValue, "%d", GeneralParamsMirror.SizesInfos.nbr_phys_inputs );
				break;
			case 9:
				sprintf( BuffLabel, "Nbr.Phys.Outputs (current alloc=%d)", InfosGene->GeneralParams.SizesInfos.nbr_phys_outputs );
				sprintf( BuffValue, "%d", GeneralParamsMirror.SizesInfos.nbr_phys_outputs );
				break;
			case 10:
				sprintf( BuffLabel, "Nbr.Phys.Words.Inputs (current alloc=%d)", InfosGene->GeneralParams.SizesInfos.nbr_phys_words_inputs );
				sprintf( BuffValue, "%d", GeneralParamsMirror.SizesInfos.nbr_phys_words_inputs );
				break;
			case 11:
				sprintf( BuffLabel, "Nbr.Phys.Words.Outputs (current alloc=%d)", InfosGene->GeneralParams.SizesInfos.nbr_phys_words_outputs );
				sprintf( BuffValue, "%d", GeneralParamsMirror.SizesInfos.nbr_phys_words_outputs );
				break;
			case 12:
				sprintf( BuffLabel, "Nbr.Arithm.Expr. (current alloc=%d)", InfosGene->GeneralParams.SizesInfos.nbr_arithm_expr );
				sprintf( BuffValue, "%d", GeneralParamsMirror.SizesInfos.nbr_arithm_expr );
				break;
			case 13:
				InfoUsed = NbrSectionsDefined( )*100/InfosGene->GeneralParams.SizesInfos.nbr_sections;
				sprintf( BuffLabel, "Nbr.Sections (%d%c used - current alloc=%d)", InfoUsed,'%', InfosGene->GeneralParams.SizesInfos.nbr_sections );
				sprintf( BuffValue, "%d", GeneralParamsMirror.SizesInfos.nbr_sections );
				break;
			case 14:
				sprintf( BuffLabel, "Nbr.Symbols (current alloc=%d)", InfosGene->GeneralParams.SizesInfos.nbr_symbols );
				sprintf( BuffValue, "%d", GeneralParamsMirror.SizesInfos.nbr_symbols );
				break;
#ifdef OLD_TIMERS_MONOS_SUPPORT
			case 15:
				sprintf( BuffLabel, "Nbr.Timers (current alloc=%d)", InfosGene->GeneralParams.SizesInfos.nbr_timers );
				sprintf( BuffValue, "%d", GeneralParamsMirror.SizesInfos.nbr_timers );
				break;
			case 16:
				sprintf( BuffLabel, "Nbr.Monostables (current alloc=%d)", InfosGene->GeneralParams.SizesInfos.nbr_monostables );
				sprintf( BuffValue, "%d", GeneralParamsMirror.SizesInfos.nbr_monostables );
				break;
#endif
			case 17:
				sprintf( BuffLabel, "Current file project" );
				sprintf( BuffValue, "%s",InfosGene->CurrentProjectFileName);
				break;                                
			case 18:
				sprintf( BuffLabel, "Default startup project" );
				sprintf( BuffValue, "%s",Preferences.DefaultProjectFileNameToLoadAtStartup);
				break;                                
			default:
				sprintf( BuffLabel, "???" );
				sprintf( BuffValue, "???" );
				break;
		}

		if ( NumObj==0 )
		{
			ValueParam[NumObj] = gtk_check_button_new_with_label( "Use real physical & serial modbus inputs/outputs only on the embedded target (not for GTK simul interface)" );
			if ( GeneralParamsMirror.RealInputsOutputsOnlyOnTarget )
				gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( ValueParam[NumObj] ), TRUE );
			gtk_box_pack_start (GTK_BOX (hbox[NumObj]), ValueParam[NumObj], FALSE, FALSE, 0);
		}
		else
		{
			LabelParam[NumObj] = gtk_label_new(BuffLabel);
			gtk_widget_set_usize(/*(GtkWidget *)*/LabelParam[NumObj],(NumObj<17)?350:180,0);
			gtk_box_pack_start (GTK_BOX (hbox[NumObj]), LabelParam[NumObj], FALSE, FALSE, 0);

			/* For numbers */
			ValueParam[NumObj] = gtk_entry_new();
			gtk_widget_set_usize(/*(GtkWidget *)*/ValueParam[NumObj],NumObj<17?50:450,0);
			gtk_box_pack_start (GTK_BOX (hbox[NumObj]), ValueParam[NumObj], FALSE, FALSE, 0);
			gtk_entry_set_text( GTK_ENTRY(ValueParam[NumObj]), BuffValue );
			gtk_editable_set_editable( GTK_EDITABLE(ValueParam[NumObj]), (NumObj<17)?TRUE:FALSE);
		}

		
		if ( NumObj==17 )
		{
			GtkWidget * ButtonSetDefaultPrj = gtk_button_new_with_label ("Use as default project");
			gtk_box_pack_start (GTK_BOX (hbox[NumObj]), ButtonSetDefaultPrj, TRUE, TRUE, 0);
			gtk_signal_connect(GTK_OBJECT (ButtonSetDefaultPrj), "clicked",
						(GtkSignalFunc)ButtonSetDefaultProject_click, 0);
		}
		if ( NumObj==18 )
		{
			GtkWidget * ButtonClearDefaultPrj = gtk_button_new_with_label ("No default project");
			gtk_box_pack_start (GTK_BOX (hbox[NumObj]), ButtonClearDefaultPrj, TRUE, TRUE, 0);
			gtk_signal_connect(GTK_OBJECT (ButtonClearDefaultPrj), "clicked",
						(GtkSignalFunc)ButtonClearDefaultProject_click, 0);
		}
	}
	gtk_widget_show_all(vbox);
	return vbox;
}
int GetOneGeneralInfo( int iNumber )
{
	char text[ 10 ];
	int value;
	strncpy( text, (char *)gtk_entry_get_text((GtkEntry *)ValueParam[ iNumber ]), 10 );
	text[ 9 ] = '\0';
	value = atoi( text );
	return value;
}
void GetGeneralParameters( void )
{
	int TheValue;

	GeneralParamsMirror.RealInputsOutputsOnlyOnTarget = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( ValueParam[0] ) );
printf("Real I/O choice:%d\n", GeneralParamsMirror.RealInputsOutputsOnlyOnTarget);

	TheValue = GetOneGeneralInfo( 1 );
	if ( TheValue<1 || TheValue>=1000 )
		TheValue = PERIODIC_REFRESH_MS_INPUTS_DEF;
	InfosGene->GeneralParams.PeriodMilliSecsTaskScanInputs = TheValue;
	GeneralParamsMirror.PeriodMilliSecsTaskScanInputs = TheValue;

	TheValue = GetOneGeneralInfo( 2 );
	if ( TheValue<1 || TheValue>=1000 )
		TheValue = PERIODIC_REFRESH_MS_DEF;
	if ( TheValue<InfosGene->GeneralParams.PeriodMilliSecsTaskScanInputs )
		TheValue = InfosGene->GeneralParams.PeriodMilliSecsTaskScanInputs;
	InfosGene->GeneralParams.PeriodMilliSecsTaskLogic = TheValue;
	GeneralParamsMirror.PeriodMilliSecsTaskLogic = TheValue;

	TheValue = GetOneGeneralInfo( 3 );
	GeneralParamsMirror.SizesInfos.nbr_rungs = TheValue;
	TheValue = GetOneGeneralInfo( 4 );
	GeneralParamsMirror.SizesInfos.nbr_bits = TheValue;
	TheValue = GetOneGeneralInfo( 5 );
	GeneralParamsMirror.SizesInfos.nbr_words = TheValue;
	TheValue = GetOneGeneralInfo( 6 );
	GeneralParamsMirror.SizesInfos.nbr_counters = TheValue;
	TheValue = GetOneGeneralInfo( 7 );
	GeneralParamsMirror.SizesInfos.nbr_timers_iec = TheValue;
	TheValue = GetOneGeneralInfo( 8 );
	GeneralParamsMirror.SizesInfos.nbr_phys_inputs = TheValue;
	TheValue = GetOneGeneralInfo( 9 );
	GeneralParamsMirror.SizesInfos.nbr_phys_outputs = TheValue;
	TheValue = GetOneGeneralInfo( 10 );
	GeneralParamsMirror.SizesInfos.nbr_phys_words_inputs = TheValue;
	TheValue = GetOneGeneralInfo( 11 );
	GeneralParamsMirror.SizesInfos.nbr_phys_words_outputs = TheValue;
	TheValue = GetOneGeneralInfo( 12 );
	GeneralParamsMirror.SizesInfos.nbr_arithm_expr = TheValue;
	TheValue = GetOneGeneralInfo( 13 );
	GeneralParamsMirror.SizesInfos.nbr_sections = TheValue;
	TheValue = GetOneGeneralInfo( 14 );
	GeneralParamsMirror.SizesInfos.nbr_symbols = TheValue;
#ifdef OLD_TIMERS_MONOS_SUPPORT
	TheValue = GetOneGeneralInfo( 15 );
	GeneralParamsMirror.SizesInfos.nbr_timers = TheValue;
	TheValue = GetOneGeneralInfo( 16 );
	GeneralParamsMirror.SizesInfos.nbr_monostables = TheValue;
#endif
}

void AddDevicesListToComboBox( GtkComboBox * pComboBox )
{
	int ScanDev = 0;
	do
	{
		gtk_combo_box_append_text( pComboBox, Devices[ ScanDev++ ] );
	}
	while( Devices[ ScanDev ] );
}

GtkWidget * CreateIOConfPage( char ForInputs )
{
	static char * Labels[] = { "First %", "Type", "PortAdr(0x)/SubDev", "First Channel", "Nbr Channels", "Logic", "ConfigData" };
	GtkWidget *vbox;
	GtkWidget *hbox[ (ForInputs?NBR_INPUTS_CONF:NBR_OUTPUTS_CONF)+1   +30];
	int NumObj;
	int NumLine;
//	GList * ItemsDevices = NULL;
//	int ScanDev = 0;
	StrIOConf * pConf;
	GtkWidget *InputParamLabel[ NBR_IO_PARAMS];
	GtkWidget *OutputParamLabel[ NBR_IO_PARAMS ];
int testpack;

//	do
//	{
//		ItemsDevices = g_list_append( ItemsDevices, Devices[ ScanDev++ ] );
//	}
//	while( Devices[ ScanDev ] );

	vbox = gtk_vbox_new (FALSE, 0);
	gtk_widget_show (vbox);

	for (NumLine=-1; NumLine<(ForInputs?NBR_INPUTS_CONF:NBR_OUTPUTS_CONF); NumLine++ )
	{
		hbox[NumLine+1] = gtk_hbox_new (FALSE, 0);
		gtk_container_add (GTK_CONTAINER (vbox), hbox[NumLine+1]);
		
		gtk_widget_show (hbox[NumLine+1]);
		for (NumObj=0; NumObj<NBR_IO_PARAMS; NumObj++)
		{
			if ( NumLine==-1 )
			{
				GtkWidget **IOParamLabel = ForInputs?&InputParamLabel[ NumObj ]:&OutputParamLabel[ NumObj ];
				if ( NumObj==0 )
					*IOParamLabel = gtk_label_new( ForInputs?"1st %I mapped":"1st %Q mapped" );
				else
					*IOParamLabel = gtk_label_new( Labels[ NumObj ] );
				gtk_widget_set_size_request( *IOParamLabel,(NumObj==1 || NumObj==2)?130:105,-1 );
				gtk_box_pack_start(GTK_BOX (hbox[ NumLine+1 ]), *IOParamLabel, FALSE, FALSE, 0);
				gtk_widget_show( *IOParamLabel );
			}
			else
			{
				char BuffValue[ 30 ];
				if ( ForInputs )
					pConf = &InfosGene->InputsConf[ NumLine ];
				else
					pConf = &InfosGene->OutputsConf[ NumLine ];

				switch( NumObj )
				{
					/* For devices */
					case 1:
					{
						int ComboValueToDisplay = 0;
//////						if ( pConf->FirstClassicLadderIO==-1 )
//////						{
//////							ValueToDisplay = 0;
//////						}
//////						else
						{
							if ( pConf->DeviceType==DEVICE_TYPE_DIRECT_ACCESS )
								ComboValueToDisplay = 1;
							else if ( pConf->DeviceType==DEVICE_TYPE_DIRECT_CONFIG )
								ComboValueToDisplay = 2;
							else if ( pConf->DeviceType>=DEVICE_TYPE_COMEDI )
								ComboValueToDisplay = pConf->DeviceType-DEVICE_TYPE_COMEDI+3;
						}
						{
							GtkWidget **IOParamDevice = ForInputs?&InputDeviceParam[ NumLine ]:&OutputDeviceParam[ NumLine ];
//							*IOParamDevice = gtk_combo_new( );
//							gtk_combo_set_value_in_list( GTK_COMBO(*IOParamDevice), TRUE /*val*/, FALSE /*ok_if_empty*/ );
//							gtk_combo_set_popdown_strings( GTK_COMBO(*IOParamDevice), ItemsDevices );
							*IOParamDevice = gtk_combo_box_new_text();
							AddDevicesListToComboBox( GTK_COMBO_BOX( *IOParamDevice ) );
							gtk_widget_set_size_request( *IOParamDevice,130,-1 );
							gtk_box_pack_start ( GTK_BOX (hbox[NumLine+1]), *IOParamDevice, FALSE, FALSE, 0 );
							gtk_widget_show ( *IOParamDevice );
//							gtk_entry_set_text((GtkEntry*)((GtkCombo *)*IOParamDevice)->entry,Devices[ ValueToDisplay ]);
							gtk_combo_box_set_active( GTK_COMBO_BOX( *IOParamDevice ), ComboValueToDisplay );
						}
						break;
					}
					/* For flags */
					case 5:
					{
						GtkWidget **IOParamFlag = ForInputs?&InputFlagParam[ NumLine ]:&OutputFlagParam[ NumLine ];
						*IOParamFlag = gtk_check_button_new_with_label( "Inverted" );
						gtk_widget_set_size_request( *IOParamFlag,105,-1 );
						gtk_box_pack_start( GTK_BOX (hbox[NumLine+1]), *IOParamFlag, FALSE, FALSE, 0 );
						gtk_widget_show ( *IOParamFlag );
						if ( pConf->FlagInverted )
							gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( *IOParamFlag ), TRUE );
						break;
					}
					/* For numbers */
					default:
					{
						switch( NumObj )
						{
							case 0:
								if ( pConf->FirstClassicLadderIO==-1 )
									strcpy( BuffValue, "" );
								else
									sprintf( BuffValue, "%d", pConf->FirstClassicLadderIO );
								break;
							case 2:
								if ( pConf->DeviceType==DEVICE_TYPE_DIRECT_ACCESS || pConf->DeviceType==DEVICE_TYPE_DIRECT_CONFIG )
									sprintf( BuffValue, "%X", pConf->SubDevOrAdr );
								else
									sprintf( BuffValue, "%d", pConf->SubDevOrAdr );
								break;
							case 3:
								sprintf( BuffValue, "%d", pConf->FirstChannel ); break;
							case 4:
								sprintf( BuffValue, "%d", pConf->NbrConsecutivesChannels ); break;
							case 6:
								sprintf( BuffValue, "%d", pConf->ConfigData ); break;
						}
						{
							GtkWidget **IOParamEntry = ForInputs?&InputParamEntry[ NumLine ][ NumObj ]:&OutputParamEntry[ NumLine ][ NumObj ];
							*IOParamEntry = gtk_entry_new( );
							gtk_widget_set_size_request( *IOParamEntry,(NumObj==1 || NumObj==2)?130:105,-1 );
							gtk_box_pack_start( GTK_BOX (hbox[NumLine+1]), *IOParamEntry, FALSE, FALSE, 0 );
							gtk_widget_show ( *IOParamEntry );
							gtk_entry_set_text( GTK_ENTRY(*IOParamEntry), BuffValue );
						}
						break;
					}
				}
			}
		}//for (NumObj=0;
	}

//TODO: I've not found how to not have all the hbox vertically expanded...?
for(testpack=0; testpack<30; testpack++)
{		
		hbox[(ForInputs?NBR_INPUTS_CONF:NBR_OUTPUTS_CONF)+1+testpack] = gtk_hbox_new (FALSE, 0);
		gtk_container_add (GTK_CONTAINER (vbox), hbox[(ForInputs?NBR_INPUTS_CONF:NBR_OUTPUTS_CONF)+1+testpack]);
//gtk_box_pack_start(GTK_BOX(vbox), hbox[ (ForInputs?NBR_INPUTS_CONF:NBR_OUTPUTS_CONF)+1+testpack ], TRUE, TRUE, 0);
		gtk_widget_show (hbox[(ForInputs?NBR_INPUTS_CONF:NBR_OUTPUTS_CONF)+1+testpack]);
}

	
	return vbox;
}

// no more usefull with new widgets gtk_combo_box_new_text( )...
/*int ConvComboToNum( char * text, char ** list )
{
	int Value = 0;
	char Found = FALSE;
	while( !Found && list[ Value ]!=NULL )
	{
		if ( strcmp( list[ Value ], text )==0 )
			Found = TRUE;
		else
			Value++;
	}
	return Value;
}*/
void GetIOSettings( char ForInputs )
{
	int NumObj;
	int NumLine;
	StrIOConf * pConf;
	int ComboVal;
	GtkWidget **IOParamDevice;
	GtkWidget **IOParamEntry;
	GtkWidget **IOParamFlag;
	char * text;
	for (NumLine=0; NumLine<(ForInputs?NBR_INPUTS_CONF:NBR_OUTPUTS_CONF); NumLine++ )
	{
		if ( ForInputs )
			pConf = &InfosGene->InputsConf[ NumLine ];
		else
			pConf = &InfosGene->OutputsConf[ NumLine ];

		pConf->FirstClassicLadderIO = -1;
		pConf->FlagInverted = 0;

		IOParamDevice = ForInputs?&InputDeviceParam[ NumLine ]:&OutputDeviceParam[ NumLine ];
//		ComboVal = ConvComboToNum( (char *)gtk_entry_get_text((GtkEntry *)((GtkCombo *)*IOParamDevice)->entry), Devices );
		ComboVal = gtk_combo_box_get_active( GTK_COMBO_BOX( *IOParamDevice ) );
		if ( ComboVal>0 )
		{
			int FirstIO = -1;
			int DeviceTypeValue = DEVICE_TYPE_NONE;
			if ( ComboVal==1 )
				DeviceTypeValue = DEVICE_TYPE_DIRECT_ACCESS;
			else if ( ComboVal==2 )
				DeviceTypeValue = DEVICE_TYPE_DIRECT_CONFIG;
			else
				DeviceTypeValue = DEVICE_TYPE_COMEDI+ComboVal-3;
			IOParamFlag = ForInputs?&InputFlagParam[ NumLine ]:&OutputFlagParam[ NumLine ];
			if ( gtk_toggle_button_get_active ( GTK_TOGGLE_BUTTON( *IOParamFlag ) ) )
				pConf->FlagInverted = 1;
			for (NumObj=0; NumObj<NBR_IO_PARAMS; NumObj++)
			{
				IOParamEntry = ForInputs?&InputParamEntry[ NumLine ][ NumObj ]:&OutputParamEntry[ NumLine ][ NumObj ];
				switch( NumObj )
				{
					case 0:
						text = (char *)gtk_entry_get_text((GtkEntry *)*IOParamEntry);
						if ( text[0]!='\0' )
							FirstIO = atoi( text );
						break;
					case 2:
						text = (char *)gtk_entry_get_text((GtkEntry *)*IOParamEntry);
						if ( DeviceTypeValue==DEVICE_TYPE_DIRECT_ACCESS || DeviceTypeValue==DEVICE_TYPE_DIRECT_CONFIG )
							sscanf( text, "%X", &pConf->SubDevOrAdr );
						else
							pConf->SubDevOrAdr = atoi( text );
						break;
					case 3:
						text = (char *)gtk_entry_get_text((GtkEntry *)*IOParamEntry);
						pConf->FirstChannel = atoi( text );
						break;
					case 4:
						text = (char *)gtk_entry_get_text((GtkEntry *)*IOParamEntry);
						pConf->NbrConsecutivesChannels = atoi( text );
						break;
					case 6:
						text = (char *)gtk_entry_get_text((GtkEntry *)*IOParamEntry);
						pConf->ConfigData = (unsigned char)atoi( text );
						break;
				}
			}
			/* verify if not overflowing */
			if ( FirstIO+pConf->NbrConsecutivesChannels>( ForInputs?NBR_PHYS_INPUTS:NBR_PHYS_OUTPUTS ) )
			{
				printf("Error in I/O conf: overflow for Ixx or Qxx mapping detected...\n" );
				FirstIO = -1;
			}
			/* done at the end, do not forget multi-task ! */
			pConf->FirstClassicLadderIO = FirstIO;
			pConf->DeviceType = DeviceTypeValue;
		}//if ( ComboVal>0 )
	}
}

#ifdef MODBUS_IO_MASTER
void FillComboBoxSlavesList( GtkComboBox * pComboBox, char ListForStatsSelect, char CleanUpBefore )
{
	int ScanSlave;
	char Buff[ 80 ];
	if ( CleanUpBefore )
	{
		for( ScanSlave=0; ScanSlave<NBR_MODBUS_SLAVES+1; ScanSlave++ )
			gtk_combo_box_remove_text( pComboBox, 0 );
	}
	if ( !ListForStatsSelect )
		gtk_combo_box_append_text( pComboBox, "None" );
	for( ScanSlave=0; ScanSlave<NBR_MODBUS_SLAVES; ScanSlave++ )
	{
		/* take name from widgets (perhaps modified since displayed...) */
		char * text;
		if ( !ListForStatsSelect )
		{
			GtkWidget **IOParamEntry;
			IOParamEntry = &ModbusSlaveParamEntry[ ScanSlave ][ 1 ];
			text = (char *)gtk_entry_get_text((GtkEntry *)*IOParamEntry);
		}
		else
		{
			text = ModbusSlaveList[ ScanSlave ].SlaveAdr;
		}
		if ( text[0]=='\0' )
		{
			sprintf( Buff, "%d: not defined", ScanSlave );
		}
		else
		{
			// Modbus/RTU on serial used ?
			if ( ModbusConfig.ModbusSerialPortNameUsed[ 0 ]!='\0' )
				sprintf( Buff, "%d: SerialAdr%s", ScanSlave, text );
			else
				sprintf( Buff, "%d: %s", ScanSlave, text );
		}
		gtk_combo_box_append_text( pComboBox, Buff );
	}
}
void FillComboBoxReqType( GtkComboBox * pComboBox )
{
	int ScanDev = 0;
	do
	{
		gtk_combo_box_append_text( pComboBox, ModbusReqType[ ScanDev++ ] );
	}
	while( ModbusReqType[ ScanDev ] );
}
void UpdateSlaveListsOnRequestPage( void )
{
	int NumLine;
	for (NumLine=0; NumLine<NBR_MODBUS_MASTER_REQ; NumLine++ )
	{
		GtkWidget **IOParamEntry;
		StrModbusMasterReq * pConf = &ModbusMasterReq[ NumLine ];
		IOParamEntry = &ModbusReqParamEntry[ NumLine ][ 0/*for SlaveNum*/ ];
		FillComboBoxSlavesList( GTK_COMBO_BOX( *IOParamEntry ), FALSE/*ListForStatsSelect*/, TRUE/*CleanUpBefore*/ );
		gtk_combo_box_set_active( GTK_COMBO_BOX( *IOParamEntry ), pConf->SlaveListNum+1 );
	}
}
GtkWidget * CreateModbusModulesIO( void )
{
	static char * Labels[] = { "Slave N°", "Request Type", "1st Modbus Ele.", "Nbr of Ele", "Logic", "1st I/Q/IW/QW mapped" };
	GtkWidget *vbox;
	GtkWidget *hbox[ NBR_MODBUS_MASTER_REQ+1 ];
	int NumObj;
	int NumLine;
	GtkWidget *ModbusParamLabel[ NBR_MODBUS_REQ_PARAMS];

	vbox = gtk_vbox_new (FALSE, 0);

	for (NumLine=-1; NumLine<NBR_MODBUS_MASTER_REQ; NumLine++ )
	{
		hbox[NumLine+1] = gtk_hbox_new (FALSE, 0);
		gtk_container_add (GTK_CONTAINER (vbox), hbox[NumLine+1]);

		for (NumObj=0; NumObj<NBR_MODBUS_REQ_PARAMS; NumObj++)
		{
			GtkWidget **CurrentWidget;
			int PixelsLength = 120;
			switch( NumObj )
			{
				case 0:
					PixelsLength = 150;
					break;
				case 1:
					PixelsLength = 230;
					break;
				case 3:
					PixelsLength = 70;
					break;
				case 4:
					PixelsLength = 90;
					break;
				case 5:
					PixelsLength = 160;
					break;
			}
			/* labels line ? */
			if ( NumLine==-1 )
			{
				CurrentWidget = &ModbusParamLabel[ NumObj ];
				*CurrentWidget = gtk_label_new( Labels[ NumObj ] );
			}
			else
			{
				StrModbusMasterReq * pConf = &ModbusMasterReq[ NumLine ];
				switch( NumObj )
				{
					/* For slave index + req type (combo-list) */
					case 0:
					case 1:
					{
						CurrentWidget = &ModbusReqParamEntry[ NumLine ][ NumObj ];
						*CurrentWidget = gtk_combo_box_new_text( );
						if ( NumObj==0 )
						{
							FillComboBoxSlavesList( GTK_COMBO_BOX( *CurrentWidget ), FALSE/*ListForStatsSelect*/, FALSE/*CleanUpBefore*/ );
							gtk_combo_box_set_active( GTK_COMBO_BOX( *CurrentWidget ), pConf->SlaveListNum+1 );
						}
						else
						{
							FillComboBoxReqType( GTK_COMBO_BOX( *CurrentWidget ) );
							gtk_combo_box_set_active( GTK_COMBO_BOX( *CurrentWidget ), pConf->TypeReq );
						}
						break;
					}
					/* For flags (checkbutton)*/
					case 4:
					{
						CurrentWidget = &ModbusReqParamEntry[ NumLine ][ NumObj ];
						*CurrentWidget = gtk_check_button_new_with_label( "Inverted" );
						if ( pConf->LogicInverted )
							gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( *CurrentWidget ), TRUE );
						break;
					}
					/* For numbers/strings (edit widgets)*/
					default:
					{
						char BuffValue[ 30 ];
						switch( NumObj )
						{
							case 2:
								sprintf( BuffValue, "%d", pConf->FirstModbusElement );
								break;
							case 3:
								sprintf( BuffValue, "%d", pConf->NbrModbusElements );
								break;
							case 5:
								sprintf( BuffValue, "%d", pConf->OffsetVarMapped );
								break;
						}
						CurrentWidget = &ModbusReqParamEntry[ NumLine ][ NumObj ];
						*CurrentWidget = gtk_entry_new( );
						gtk_entry_set_text( GTK_ENTRY(*CurrentWidget), BuffValue );
						break;
					}
				}//switch( NumObj )
			}//!if ( NumLine==-1 )
			gtk_widget_set_usize(*CurrentWidget,PixelsLength,0);
			gtk_box_pack_start( GTK_BOX (hbox[NumLine+1]), *CurrentWidget, FALSE, FALSE, 0 );
		}//for (NumObj
	}//for (NumLine
	gtk_widget_show_all( vbox );
	return vbox;
}
void GetModbusModulesIOSettings( void )
{
	int NumObj;
	int NumLine;
	int SlaveSelected;
	for (NumLine=0; NumLine<NBR_MODBUS_MASTER_REQ; NumLine++ )
	{
		int MaxVars = 0;
		char DoVerify = FALSE;
		SlaveSelected = -1;
		StrModbusMasterReq * pConf = &ModbusMasterReq[ NumLine ];

		for (NumObj=0; NumObj<NBR_MODBUS_REQ_PARAMS; NumObj++)
		{
			GtkWidget **IOParamEntry;
			char * text;
			IOParamEntry = &ModbusReqParamEntry[ NumLine ][ NumObj ];
			switch( NumObj )
			{
				case 0://slave address
					SlaveSelected = gtk_combo_box_get_active( GTK_COMBO_BOX(*IOParamEntry) )-1; 
					break;
				case 1://type of request
					pConf->TypeReq = gtk_combo_box_get_active( GTK_COMBO_BOX(*IOParamEntry) );
					break;
				case 2://first element address
					text = (char *)gtk_entry_get_text((GtkEntry *)*IOParamEntry);
					pConf->FirstModbusElement = atoi( text );
					break;
				case 3://number of requested items
					text = (char *)gtk_entry_get_text((GtkEntry *)*IOParamEntry);
					pConf->NbrModbusElements = atoi( text );
					break;
				case 4://invert logic (instead of thinking of that everywhere later...)
					pConf->LogicInverted = ( gtk_toggle_button_get_active ( GTK_TOGGLE_BUTTON( *IOParamEntry ) ) )?1:0;
					break;
				case 5:// first classicladder variable map location
					text = (char *)gtk_entry_get_text((GtkEntry *)*IOParamEntry);
					pConf->OffsetVarMapped = atoi( text );
					break;
			}
		}//for (NumObj=0;
		/* a slave is defined ? */
		if ( SlaveSelected!=-1 )
		{
			/* verify if not overflowing */
			switch( pConf->TypeReq )
			{
				case MODBUS_REQ_INPUTS_READ: MaxVars = GetSizeVarsForTypeVar( ModbusConfig.MapTypeForReadInputs ); DoVerify = TRUE; break;
				case MODBUS_REQ_COILS_WRITE: MaxVars = GetSizeVarsForTypeVar( ModbusConfig.MapTypeForWriteCoils ); DoVerify = TRUE; break;
				case MODBUS_REQ_COILS_READ: MaxVars = GetSizeVarsForTypeVar( ModbusConfig.MapTypeForReadCoils ); DoVerify = TRUE; break;
				case MODBUS_REQ_INPUT_REGS_READ: MaxVars = GetSizeVarsForTypeVar( ModbusConfig.MapTypeForReadInputRegs ); DoVerify = TRUE; break;
				case MODBUS_REQ_HOLD_REGS_WRITE: MaxVars = GetSizeVarsForTypeVar( ModbusConfig.MapTypeForWriteHoldRegs ); DoVerify = TRUE; break;
				case MODBUS_REQ_HOLD_REGS_READ: MaxVars = GetSizeVarsForTypeVar( ModbusConfig.MapTypeForReadHoldRegs ); DoVerify = TRUE; break;
			}
			if ( DoVerify )
			{
				if ( pConf->OffsetVarMapped+pConf->NbrModbusElements>MaxVars )
				{
					printf("Error in I/O modbus conf: overflow for I,Q,B,IQ,WQ or W mapping detected...ASKED=%i,MAX=%i\n",  pConf->OffsetVarMapped+pConf->NbrModbusElements,MaxVars);
					SlaveSelected = -1;
					ShowMessageBox("Error","Overflow error for I,Q,B,IQ,WQ or W mapping detected...","Ok");
				}
			}
		}
		/* done at the end, do not forget multi-task ! */
		pConf->SlaveListNum = SlaveSelected;
	}//for (NumLine=0; 
}
GtkWidget * CreateModbusSlavesPage( void )
{
	static char * Labels[] = { "Slave N°", "Slave Address", "TCP/UDP mode", "Module Informations" };
	GtkWidget *vbox;
	GtkWidget *hbox[ 1+NBR_MODBUS_SLAVES ];
	int NumObj;
	int NumLine;
	GtkWidget *ModbusParamLabel[ NBR_MODBUS_SLAVES_PARAMS];

	GtkTooltips * WidgetTooltipsAdr = gtk_tooltips_new();

	vbox = gtk_vbox_new (FALSE, 0);

	for (NumLine=-1; NumLine<NBR_MODBUS_SLAVES; NumLine++ )
	{
		hbox[NumLine+1] = gtk_hbox_new (FALSE, 0);
		gtk_container_add (GTK_CONTAINER (vbox), hbox[NumLine+1]);

		for (NumObj=0; NumObj<NBR_MODBUS_SLAVES_PARAMS; NumObj++)
		{
			GtkWidget **CurrentWidget;
			int PixelsLength = 70;
			switch( NumObj )
			{
				case 1:
					PixelsLength = 180;
					break;
				case 2:
					PixelsLength = 160;
					break;
				case 3:
					PixelsLength = 240;
					break;
			}
			/* labels line ? */
			if ( NumLine==-1 )
			{
				CurrentWidget = &ModbusParamLabel[ NumObj ];
				*CurrentWidget = gtk_label_new( Labels[ NumObj ] );
			}
			else
			{
				StrModbusSlave * pSlave = &ModbusSlaveList[ NumLine ];
				switch( NumObj )
				{
					/* For flags (checkbutton)*/
					case 2:
					{
						CurrentWidget = &ModbusSlaveParamEntry[ NumLine ][ NumObj ];
						*CurrentWidget = gtk_check_button_new_with_label( "UDP instead of TCP" );
						if ( pSlave->UseUdpInsteadOfTcp )
							gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( *CurrentWidget ), TRUE );
						// can not be used for now...
						gtk_widget_set_sensitive( *CurrentWidget, FALSE );
						break;
					}
					/* For numbers/strings (edit widgets)*/
					default:
					{
						char BuffValue[ 30 ];
						switch( NumObj )
						{
							case 0:
								sprintf( BuffValue, "%d :", NumLine );
								break;
							case 1:
								strcpy( BuffValue, pSlave->SlaveAdr );
								break;
							case 3:
								strcpy( BuffValue, pSlave->NameInfo );
								break;
						}
						CurrentWidget = &ModbusSlaveParamEntry[ NumLine ][ NumObj ];
						if ( NumObj==0 )
						{
							*CurrentWidget = gtk_label_new( BuffValue );
						}
						else
						{
							*CurrentWidget = gtk_entry_new( );
							gtk_entry_set_text( GTK_ENTRY(*CurrentWidget), BuffValue );
							if ( NumObj==1 )
								gtk_tooltips_set_tip( WidgetTooltipsAdr, *CurrentWidget, "SerialAdr -or- AdrIP -or- AdrIP:Port", NULL );
						}
						break;
					}
				}//switch( NumObj )
			}//!if ( NumLine==-1 )
//			gtk_widget_set_usize(*CurrentWidget,PixelsLength,0);
			gtk_widget_set_size_request( *CurrentWidget,PixelsLength,-1 );
			gtk_box_pack_start( GTK_BOX (hbox[NumLine+1]), *CurrentWidget, FALSE, FALSE, 0 );
		}//for (NumObj
	}//for (NumLine
	gtk_widget_show_all( vbox );
	return vbox;
}
void GetModbusSlavesSettings( void )
{
	int NumObj;
	int NumLine;
	for (NumLine=0; NumLine<NBR_MODBUS_SLAVES; NumLine++ )
	{
		StrModbusSlave * pSlave = &ModbusSlaveList[ NumLine ];

		for (NumObj=0; NumObj<NBR_MODBUS_SLAVES_PARAMS; NumObj++)
		{
			GtkWidget **IOParamEntry;
			char * text;
			IOParamEntry = &ModbusSlaveParamEntry[ NumLine ][ NumObj ];
			switch( NumObj )
			{
				case 0://index, not a parameter !
					break;
				case 1://address
					text = (char *)gtk_entry_get_text((GtkEntry *)*IOParamEntry);
					strncpy( pSlave->SlaveAdr, text, LGT_SLAVE_ADR );
					pSlave->SlaveAdr[ LGT_SLAVE_ADR-1 ] = '\0';
					break;
				case 2://tdp/tcp mode
					pSlave->UseUdpInsteadOfTcp = ( gtk_toggle_button_get_active ( GTK_TOGGLE_BUTTON( *IOParamEntry ) ) )?1:0;
					break;
				case 3://information
					text = (char *)gtk_entry_get_text((GtkEntry *)*IOParamEntry);
					strncpy( pSlave->NameInfo, text, LGT_SLAVE_NAME );
					pSlave->NameInfo[ LGT_SLAVE_NAME-1 ] = '\0';
					break;
			}
		}//for (NumObj=0;
	}//for (NumLine=0; 
}

// return nbr of fields found
int SplitCommasFieldsInPointersArray( char * LineDatas, char * PtrFieldsDatasFound[], int NbrMaxFields )
{
	int ScanField;
	for( ScanField=0; ScanField<NbrMaxFields; ScanField++ )
		PtrFieldsDatasFound[ ScanField ] = NULL;
	ScanField = 0;
	PtrFieldsDatasFound[ ScanField++ ] = LineDatas;
	do
	{
		do
		{
			// comma ?
			if ( *LineDatas==',' && *(LineDatas+1)!='\0' )
			{
				// test if not an empty field...
				if ( *(LineDatas+1)!=',' )
				{
					PtrFieldsDatasFound[ ScanField ] = LineDatas+1;
					*LineDatas = '\0';
				}
				ScanField++;
			}
			LineDatas++;
		}
		while( ScanField<NbrMaxFields-1 && *LineDatas!='\0' );
	}
	while( ScanField<NbrMaxFields-1 && *LineDatas!='\0' );
	return ScanField;
}
void SignalStatisticsSlaveSelect( GtkComboBox * pCombo, gpointer user_data )
{
	char BuffValue[ 100 ];
	int NumSlave = gtk_combo_box_get_active( GTK_COMBO_BOX(ComboSlaveStatsSelect) );
	GetSocketModbusMasterStats( NumSlave, BuffValue );
	gtk_label_set_text( GTK_LABEL(LabelStatsResults), BuffValue );
}
GtkWidget * CreateModbusComParametersPage( void )
{
	GtkWidget *vbox;
	GtkWidget *hbox[ NBR_COM_PARAMS +1 ];
	GtkWidget * LabelComParam[ NBR_COM_PARAMS +1 ];
	int NumLine;
	char BuffLabel[ 50 ];
	char BuffValue[ 100 ];

	vbox = gtk_vbox_new (FALSE/*homogeneous*/, 0);
	gtk_widget_show (vbox);
	for( NumLine=0; NumLine<NBR_COM_PARAMS; NumLine++ )
	{
		hbox[NumLine] = gtk_hbox_new (FALSE, 0);
		gtk_container_add (GTK_CONTAINER (vbox), hbox[NumLine]);
		gtk_widget_show (hbox[NumLine]);
		switch( NumLine )
		{
			case 0:
				sprintf( BuffLabel, "Modbus master Serial port (blank = IP mode)" );
				strcpy( BuffValue, ModbusConfig.ModbusSerialPortNameUsed );
				break;
			case 1:
				sprintf( BuffLabel, "Serial baud rate" );
				sprintf( BuffValue, "%d", ModbusConfig.ModbusSerialSpeed );
				break;
			case 2:
				sprintf( BuffLabel, "Serial nbr. data bits" );
				sprintf( BuffValue, "%d,5,6,7,8", ModbusConfig.ModbusSerialDataBits-5 );
				break;
			case 3:
				sprintf( BuffLabel, "Serial parity" );
				sprintf( BuffValue, "%d,None,Odd,Even", ModbusConfig.ModbusSerialParity );
				break;
			case 4:
				sprintf( BuffLabel, "Serial nbr. stops bits" );
				sprintf( BuffValue, "%d,1,2", ModbusConfig.ModbusSerialStopBits-1 );
				break;
			case 5:
				sprintf( BuffLabel, "After transmit pause - milliseconds" );
				sprintf( BuffValue, "%d", ModbusConfig.ModbusTimeAfterTransmit );
				break;
			case 6:
				sprintf( BuffLabel, "After receive pause - milliseconds" );
				sprintf( BuffValue, "%d", ModbusConfig.ModbusTimeInterFrame );
				break;
			case 7:
				sprintf( BuffLabel, "Request Timeout length - milliseconds" );
				sprintf( BuffValue, "%d", ModbusConfig.ModbusTimeOutReceipt );
				break;
			case 8:
				sprintf( BuffLabel, "Use RTS signal to send" );
				sprintf( BuffValue, "%d,NO,YES", ModbusConfig.ModbusSerialUseRtsToSend );
				break;
			case 9:
				sprintf( BuffLabel, "Modbus element offset" );
				sprintf( BuffValue, "%d,0,1", ModbusConfig.ModbusEleOffset );
				break;
			case 10:
				sprintf( BuffLabel, "Debug level" );
				sprintf( BuffValue, "%d,QUIET,LEVEL 1,LEVEL 2,VERBOSE", ModbusConfig.ModbusDebugLevel );
				break;
			case 11:
				sprintf( BuffLabel, "Read inputs map to" );
				sprintf( BuffValue, "%d,\%%B,\%%Q,\%%I", ModbusConfig.MapTypeForReadInputs==VAR_MEM_BIT?0:(ModbusConfig.MapTypeForReadInputs==VAR_PHYS_OUTPUT?1:2) );
				break;
			case 12:
				sprintf( BuffLabel, "Read coils map to" );
				sprintf( BuffValue, "%d,\%%B,\%%Q,\%%I", ModbusConfig.MapTypeForReadCoils==VAR_MEM_BIT?0:(ModbusConfig.MapTypeForReadCoils==VAR_PHYS_OUTPUT?1:2) );
				break;
			case 13:
				sprintf( BuffLabel, "Write coils map from" );
				sprintf( BuffValue, "%d,\%%B,\%%Q,\%%I", ModbusConfig.MapTypeForWriteCoils==VAR_MEM_BIT?0:(ModbusConfig.MapTypeForWriteCoils==VAR_PHYS_OUTPUT?1:2) );
				break;
			case 14:
				sprintf( BuffLabel, "Read input registers map to" );
				sprintf( BuffValue, "%d,\%%W,\%%QW,\%%IW", ModbusConfig.MapTypeForReadInputRegs==VAR_MEM_WORD?0:(ModbusConfig.MapTypeForReadInputRegs==VAR_PHYS_WORD_OUTPUT?1:2) );
				break;
			case 15:
				sprintf( BuffLabel, "Read hold registers map to" );
				sprintf( BuffValue, "%d,\%%W,\%%QW,\%%IW", ModbusConfig.MapTypeForReadHoldRegs==VAR_MEM_WORD?0:(ModbusConfig.MapTypeForReadHoldRegs==VAR_PHYS_WORD_OUTPUT?1:2) );
				break;
			case 16:
				sprintf( BuffLabel, "Write hold registers map from" );
				sprintf( BuffValue, "%d,\%%W,\%%QW,\%%IW", ModbusConfig.MapTypeForWriteHoldRegs==VAR_MEM_WORD?0:(ModbusConfig.MapTypeForWriteHoldRegs==VAR_PHYS_WORD_OUTPUT?1:2) );
				break;
		}

		/* Labels */
		LabelComParam[NumLine] = gtk_label_new(BuffLabel);
		gtk_widget_set_usize( LabelComParam[NumLine],320,0 );
		gtk_box_pack_start( GTK_BOX(hbox[NumLine]), LabelComParam[NumLine], FALSE, FALSE, 0 );
		gtk_widget_show( LabelComParam[NumLine] );

		if ( NumLine<=1 || ( NumLine>=5 && NumLine<=7 ) )
		{
			/* Simple Integer Values */
			EntryComParam[NumLine] = gtk_entry_new();
			gtk_widget_set_usize( EntryComParam[NumLine],125,0 );
			gtk_box_pack_start( GTK_BOX(hbox[NumLine]), EntryComParam[NumLine], FALSE, FALSE, 0 );
			gtk_widget_show( EntryComParam[NumLine] );
			gtk_entry_set_text( GTK_ENTRY(EntryComParam[NumLine]), BuffValue );
		}
		else
		{
			/* Radio buttons Values */
			/* BuffValue: first=n° selected , others=labels for each radio button */
			char * PtrArraysCsv[10];
			int CreateRadioBut;
			for( CreateRadioBut=0; CreateRadioBut<NBR_RADIO_BUT_COM_PARAMS; CreateRadioBut++ )
				RadioButComParams[ NumLine ][ CreateRadioBut ] = NULL;
			int NbrInfos = SplitCommasFieldsInPointersArray( BuffValue, PtrArraysCsv, 10 );
			if ( NbrInfos>2 )
			{
				int ValueSelected = atoi( PtrArraysCsv[0] );
				for( CreateRadioBut=0; CreateRadioBut<NbrInfos-1; CreateRadioBut++ )
				{
					char * label = PtrArraysCsv[1+CreateRadioBut];
					if ( CreateRadioBut==0 )
						RadioButComParams[ NumLine ][ CreateRadioBut ]= gtk_radio_button_new_with_label( NULL, label );
					else
						RadioButComParams[ NumLine ][ CreateRadioBut ]= gtk_radio_button_new_with_label_from_widget( GTK_RADIO_BUTTON(RadioButComParams[NumLine][0]), label );
					gtk_box_pack_start (GTK_BOX (hbox[NumLine]), RadioButComParams[ NumLine ][ CreateRadioBut ], FALSE, TRUE, 0);
					gtk_widget_show( RadioButComParams[ NumLine ][ CreateRadioBut ] );
					if ( CreateRadioBut==ValueSelected )
						gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( RadioButComParams[ NumLine ][ CreateRadioBut ] ), TRUE);
				}
			}
		}
	}

	// some statistics... to debug my AVR I/O module !
	NumLine = NBR_COM_PARAMS +1;
	hbox[NumLine] = gtk_hbox_new (FALSE, 0);
	gtk_container_add (GTK_CONTAINER (vbox), hbox[NumLine]);
	gtk_widget_show (hbox[NumLine]);
	LabelComParam[NumLine] = gtk_label_new( "Modbus I/O module master stats for slave:" );
//	gtk_widget_set_usize( LabelComParam[NumLine],250,0 );
	gtk_box_pack_start( GTK_BOX(hbox[NumLine]), LabelComParam[NumLine], FALSE, FALSE, 0 );
	gtk_widget_show( LabelComParam[NumLine] );
	ComboSlaveStatsSelect = gtk_combo_box_new_text( );
	FillComboBoxSlavesList( GTK_COMBO_BOX( ComboSlaveStatsSelect ), TRUE/*ListForStatsSelect*/, FALSE/*CleanUpBefore*/ );
	gtk_combo_box_set_active( GTK_COMBO_BOX( ComboSlaveStatsSelect ), 0 );
	gtk_box_pack_start( GTK_BOX(hbox[NumLine]), ComboSlaveStatsSelect, FALSE, FALSE, 0 );
	gtk_widget_show( ComboSlaveStatsSelect );
	gtk_signal_connect( GTK_OBJECT(ComboSlaveStatsSelect), "changed",
                                        (GtkSignalFunc) SignalStatisticsSlaveSelect, (void *)NULL );
	GetSocketModbusMasterStats( /*TODO, choose slave wanted!*/0, BuffValue );
	LabelStatsResults = gtk_label_new( BuffValue );
//	gtk_widget_set_usize( LabelStatsResults,250,0 );
	gtk_box_pack_start( GTK_BOX(hbox[NumLine]), LabelStatsResults, FALSE, FALSE, 0 );
	gtk_widget_show( LabelStatsResults );

	return vbox;
}
int GetRadioButValueSelected( int NumLineToSee )
{
	int Sel = 0;
	int ScanRadioBut;
	for( ScanRadioBut=0; ScanRadioBut<NBR_RADIO_BUT_COM_PARAMS; ScanRadioBut++ )
	{
		if ( RadioButComParams[ NumLineToSee ][ ScanRadioBut ]!=NULL )
		{
			if ( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( RadioButComParams[ NumLineToSee ][ ScanRadioBut ] ) ) )
				Sel = ScanRadioBut;
		}
	}
	return Sel;	
}
void GetModbusComParameters( void )
{
	strcpy( ModbusConfig.ModbusSerialPortNameUsed, gtk_entry_get_text(GTK_ENTRY( EntryComParam[ 0 ] )));
	ModbusConfig.ModbusSerialSpeed = atoi( gtk_entry_get_text(GTK_ENTRY( EntryComParam[ 1 ] )) );
	ModbusConfig.ModbusSerialDataBits = GetRadioButValueSelected( 2 )+5;
	ModbusConfig.ModbusSerialParity = GetRadioButValueSelected( 3 ); 
	ModbusConfig.ModbusSerialStopBits = GetRadioButValueSelected( 4 )+1;
	ModbusConfig.ModbusTimeAfterTransmit = atoi( gtk_entry_get_text(GTK_ENTRY( EntryComParam[ 5 ] )) );
	ModbusConfig.ModbusTimeInterFrame = atoi( gtk_entry_get_text(GTK_ENTRY( EntryComParam[ 6 ] )) );
	ModbusConfig.ModbusTimeOutReceipt = atoi( gtk_entry_get_text(GTK_ENTRY( EntryComParam[ 7 ] )) );
	ModbusConfig.ModbusSerialUseRtsToSend = GetRadioButValueSelected( 8 );
	ModbusConfig.ModbusEleOffset = GetRadioButValueSelected( 9 );
	ModbusConfig.ModbusDebugLevel = GetRadioButValueSelected( 10 );
	// ! after here, 2 tests per line... ( if a parameter is added before ! ;-) )
	ModbusConfig.MapTypeForReadInputs = GetRadioButValueSelected( 11 )==0?VAR_MEM_BIT:(GetRadioButValueSelected( 11 )==1?VAR_PHYS_OUTPUT:VAR_PHYS_INPUT);
	ModbusConfig.MapTypeForReadCoils = GetRadioButValueSelected( 12 )==0?VAR_MEM_BIT:(GetRadioButValueSelected( 12 )==1?VAR_PHYS_OUTPUT:VAR_PHYS_INPUT);
	ModbusConfig.MapTypeForWriteCoils = GetRadioButValueSelected( 13 )==0?VAR_MEM_BIT:(GetRadioButValueSelected( 13 )==1?VAR_PHYS_OUTPUT:VAR_PHYS_INPUT);
	ModbusConfig.MapTypeForReadInputRegs = GetRadioButValueSelected( 14 )==0?VAR_MEM_WORD:(GetRadioButValueSelected( 14 )==1?VAR_PHYS_WORD_OUTPUT:VAR_PHYS_WORD_INPUT);
	ModbusConfig.MapTypeForReadHoldRegs = GetRadioButValueSelected( 15 )==0?VAR_MEM_WORD:(GetRadioButValueSelected( 15 )==1?VAR_PHYS_WORD_OUTPUT:VAR_PHYS_WORD_INPUT);
	ModbusConfig.MapTypeForWriteHoldRegs = GetRadioButValueSelected( 16 )==0?VAR_MEM_WORD:(GetRadioButValueSelected( 16 )==1?VAR_PHYS_WORD_OUTPUT:VAR_PHYS_WORD_INPUT);
}
#endif


#ifdef COMPLETE_PLC
GtkWidget * CreateConfigEventsPage( void )
{
	static char * Labels[] = { "1st %MBxxxx", "Nbr Of %MB", "Symbol", "Text event", "Tag(>0=Def)" };
	GtkWidget *vbox;
	GtkWidget *hbox[ NBR_CONFIG_EVENTS_LOG+2 ];
	int NumObj;
	int NumLine;
	StrConfigEventLog * pCfgEvtLog;
	char BuffValue[ 40 ];

	vbox = gtk_vbox_new (FALSE, 0);
	gtk_widget_show (vbox);

	for (NumLine=-1; NumLine<NBR_CONFIG_EVENTS_LOG; NumLine++ )
	{
		hbox[NumLine+1] = gtk_hbox_new (FALSE, 0);
		gtk_container_add (GTK_CONTAINER (vbox), hbox[NumLine+1]);
		gtk_widget_show (hbox[NumLine+1]);

		for (NumObj=0; NumObj<NBR_CONFIG_EVENTS_PARAMS; NumObj++)
		{
			switch( NumLine )
			{
				case -1:
				{
					int PixelsLength = 100;
					GtkWidget * ParamTitleLabel;
					switch( NumObj )
					{
						case 3:
							PixelsLength = 220;
							break;
					}
					ParamTitleLabel = gtk_label_new( Labels[ NumObj ] );
					gtk_widget_set_usize(ParamTitleLabel,PixelsLength,0);
					gtk_box_pack_start(GTK_BOX (hbox[ NumLine+1 ]), ParamTitleLabel, FALSE, FALSE, 0);
					gtk_widget_show( ParamTitleLabel );
					break;
				}
				default:
				{
					pCfgEvtLog = &ConfigEventLog[ NumLine ];
					int PixelsLength = 100;
					int MaxChars = 0;
					switch( NumObj )
					{
						case 0:
							if ( pCfgEvtLog->FirstVarNum!=-1 )
								sprintf( BuffValue, "%d", pCfgEvtLog->FirstVarNum );
							else
								BuffValue[ 0 ] = '\0';
							break;
						case 1:
							sprintf( BuffValue, "%d", pCfgEvtLog->NbrVars );
							break;
						case 2:
							strcpy( BuffValue, pCfgEvtLog->Symbol );
							MaxChars = EVENT_SYMBOL_LGT-1;
							break;
						case 3:
							strcpy( BuffValue, pCfgEvtLog->Text );
							PixelsLength = 220;
							MaxChars = EVENT_TEXT_LGT-1;
							break;
						case 4:
							sprintf( BuffValue, "%d", pCfgEvtLog->EventType );
							break;
					}
					{
						GtkWidget **ParamEntry = &EventConfigParamEntry[ NumLine ][ NumObj ];
						*ParamEntry = gtk_entry_new( );
						gtk_widget_set_usize( *ParamEntry,PixelsLength,0 );
						if ( MaxChars>0 )
							gtk_entry_set_max_length( GTK_ENTRY(*ParamEntry), MaxChars );
						gtk_box_pack_start( GTK_BOX (hbox[NumLine+1]), *ParamEntry, FALSE, FALSE, 0 );
						gtk_widget_show ( *ParamEntry );
						gtk_entry_set_text( GTK_ENTRY(*ParamEntry), BuffValue );
					}
				}//default:
			}
		}
	}
	return vbox;
}
void GetConfigEventsSettings( void )
{
	int NumObj;
	int NumLine;
	StrConfigEventLog * pCfgEvtLog;
	GtkWidget *ParamEntry;
	char * text;
	for (NumLine=0; NumLine<NBR_CONFIG_EVENTS_LOG; NumLine++ )
	{
		int FirstVarEntered = -1;
		int NbrVarsEntered = 0;
		pCfgEvtLog = &ConfigEventLog[ NumLine ];

		for (NumObj=0; NumObj<NBR_CONFIG_EVENTS_PARAMS; NumObj++)
		{
			ParamEntry = EventConfigParamEntry[ NumLine ][ NumObj ];
			switch( NumObj )
			{
				case 0:
					text = (char *)gtk_entry_get_text(GTK_ENTRY(ParamEntry));
					if ( text[0]!='\0' )
						FirstVarEntered = atoi( text );
					break;
				case 1:
					text = (char *)gtk_entry_get_text(GTK_ENTRY(ParamEntry));
					NbrVarsEntered = atoi( text );
					break;
				case 2:
					text = (char *)gtk_entry_get_text(GTK_ENTRY(ParamEntry));
					strcpy( pCfgEvtLog->Symbol, text );
					break;
				case 3:
					text = (char *)gtk_entry_get_text(GTK_ENTRY(ParamEntry));
					strcpy( pCfgEvtLog->Text, text );
					break;
				case 4:
					text = (char *)gtk_entry_get_text(GTK_ENTRY(ParamEntry));
					pCfgEvtLog->EventType = atoi( text );
					break;
			}
		}//for (NumObj=0;
		pCfgEvtLog->FirstVarNum = -1;
		if ( FirstVarEntered+NbrVarsEntered>GetSizeVarsForTypeVar( VAR_MEM_BIT ) )
		{
			ShowMessageBox("Error","Overflow error for first/nbrs detected...","Ok");
		}
		else
		{
			pCfgEvtLog->NbrVars = NbrVarsEntered;
			pCfgEvtLog->FirstVarNum = FirstVarEntered;
		}
	}//for (NumLine=0; 
	// update the tags list of the variables that the user want to log !
	InitVarsArrayLogTags( );
}
#endif


void GetSettings( void )
{
	int Scan;
	GetGeneralParameters( );
	GetIOSettings( 1/*ForInputs*/ );
	GetIOSettings( 0/*ForInputs*/ );
#ifdef MODBUS_IO_MASTER
	// disable before all requests on slave (multi-task...)
	for (Scan=0; Scan<NBR_MODBUS_MASTER_REQ; Scan++ )
		ModbusMasterReq[ Scan ].SlaveListNum = -1;
	GetModbusModulesIOSettings( );
	GetModbusSlavesSettings( );
	GetModbusComParameters( );
#endif
#ifdef COMPLETE_PLC
	GetConfigEventsSettings( );
#endif
#ifndef RT_SUPPORT
//	ConfigHardware( );
	InfosGene->AskToConfHardInputs = TRUE;
	InfosGene->AskToConfHardOutputs = TRUE;
#endif
ConfigSerialModbusMaster( );
}

/* To update slave adress list of the widgets (perhaps modified) when we go on the requests page */
void SignalPageSelected( GtkNotebook * notebook, GtkNotebookPage * page, guint page_num, gpointer user_data )
{
	if ( page_num==6 )
		UpdateSlaveListsOnRequestPage( );
}

void OpenConfigWindowGtk()
{
	GtkWidget *nbook;

	ConfigWindow = gtk_window_new (GTK_WINDOW_TOPLEVEL);
	gtk_window_set_title( GTK_WINDOW(ConfigWindow), "Config" );
	gtk_window_set_modal( GTK_WINDOW(ConfigWindow), TRUE );

	nbook = gtk_notebook_new( );
	gtk_notebook_append_page( GTK_NOTEBOOK(nbook), CreateGeneralParametersPage( ),
				 gtk_label_new ("Period/Sizes/Info") );
#ifdef COMPLETE_PLC
	gtk_notebook_append_page( GTK_NOTEBOOK(nbook), CreateConfigEventsPage( ),
				 gtk_label_new ("Events Config") );
#endif
	gtk_notebook_append_page( GTK_NOTEBOOK(nbook), CreateIOConfPage( 1/*ForInputs*/ ),
				 gtk_label_new ("Physical Inputs") );
	gtk_notebook_append_page( GTK_NOTEBOOK(nbook), CreateIOConfPage( 0/*ForInputs*/ ),
				 gtk_label_new ("Physical Outputs") );
#ifdef MODBUS_IO_MASTER
	gtk_notebook_append_page( GTK_NOTEBOOK(nbook), CreateModbusComParametersPage( ),
				 gtk_label_new ("Modbus communication setup") );
	gtk_notebook_append_page( GTK_NOTEBOOK(nbook), CreateModbusSlavesPage( ),
				 gtk_label_new ("Modbus slaves setup") );
	gtk_notebook_append_page( GTK_NOTEBOOK(nbook), CreateModbusModulesIO( ),
				 gtk_label_new ("Modbus I/O setup") );
#endif

	gtk_container_add( GTK_CONTAINER (ConfigWindow), nbook );
	gtk_widget_show( nbook );
	gtk_signal_connect( GTK_OBJECT(nbook), "switch-page",
                                        (GtkSignalFunc) SignalPageSelected, (void *)NULL );

	gtk_window_set_position( GTK_WINDOW(ConfigWindow), GTK_WIN_POS_CENTER );
//	gtk_window_set_policy( GTK_WINDOW(ConfigWindow), FALSE, FALSE, TRUE );
	gtk_signal_connect ( GTK_OBJECT(ConfigWindow), "destroy",
                        GTK_SIGNAL_FUNC(GetSettings), NULL );

	gtk_widget_show( ConfigWindow );
}


